#ifndef _SPRITE_
#define _SPRITE_

// Sprite is main draw class.
// use this instead of others, because if you want to change from HGE to another
// graphic system you just need to change this class.
class Sprite
{
private:
	hgeQuad quad;
	b2Vec2 _pos[4];
	b2Vec2 _scale;
	float32 _angle;
public:
	Sprite()
	{
		// Default initiate.
		float tx[4] = {0,1,1,0};
		float ty[4] = {0,0,1,1};
		SetTexSize(tx,ty);
		SetColor(0xFFFFFFFF);
		SetBlend(BLEND_COLORMUL | BLEND_ALPHABLEND | BLEND_NOZWRITE);
		Visible = true;
		_scale = b2Vec2(1,1);
		_angle = 0;
		quad.tex = 0;
		Inverted = false;
	}
	bool Visible;
	bool Inverted;
	HTEXTURE GetTexture()
	{
		return quad.tex;
	}
	// Path can be full or nor.
	bool LoadTexture(char * path)
	{
		return ((quad.tex = hge->Texture_Load(path)) != 0);
	}
	// Index means a vertex of quad.
	void SetColor(DWORD color, int index = -1)
	{
		if (index == -1)
		{
			quad.v[0].col = color;
			quad.v[1].col = color;
			quad.v[2].col = color;
			quad.v[3].col = color;
		}
		else
			quad.v[index].col = color;
	}
	DWORD GetColor(int index = 0)
	{
		return quad.v[index].col;
	}
	void SetBlend(int blend)
	{
		quad.blend = blend;
	}
	int GetBlend()
	{
		return quad.blend;
	}
	void SetVertex(hgeVertex v, int index)
	{
		quad.v[index] = v;
	}
	hgeVertex GetVertex(int index)
	{
		return quad.v[index];
	}
	hgeQuad * GetQuad()
	{
		return &quad;
	}
	// Get center (only tested with rectangles and squares).
	b2Vec2 GetCenter()
	{
		return b2Vec2(GetRealSize()[2].x/2 + _pos[0].x,GetRealSize()[2].y/2 + _pos[0].y);
	}
	// Draw function.
	// It draws quad at CENTER of position.
	void Draw()
	{
		if(!Visible)
			return;
		b2Vec2 * DrawCorners = GetCornersAngled();
		quad.v[0].x = DrawCorners[0].x - GetRealSize()[2].x/2;	quad.v[0].y = DrawCorners[0].y - GetRealSize()[2].y/2;
		quad.v[1].x = DrawCorners[1].x - GetRealSize()[2].x/2;	quad.v[1].y = DrawCorners[1].y - GetRealSize()[2].y/2;
		quad.v[2].x = DrawCorners[2].x - GetRealSize()[2].x/2;	quad.v[2].y = DrawCorners[2].y - GetRealSize()[2].y/2;
		quad.v[3].x = DrawCorners[3].x - GetRealSize()[2].x/2; quad.v[3].y = DrawCorners[3].y - GetRealSize()[2].y/2;
		hge->Gfx_RenderQuad(&quad);
	}
	// Texture size must be beetwen 0 and 1.
	void SetTexSize(float tx[4], float ty[4])
	{
		for (int i = 0;i<4;i++)
		{
			quad.v[i].tx = tx[i];
			quad.v[i].ty = ty[i];
		}
	}
	// WARNING:
	// GetTexSize returns whole texture size, not value beetwen 0 and 1.
	// If you texture is 250x250, it returns (250,250).
	b2Vec2 GetTexSize()
	{
		if (GetTexture() == 0)
			return b2Vec2_zero;
		return b2Vec2(FLOAT(hge->Texture_GetWidth(GetTexture())),FLOAT(hge->Texture_GetHeight(GetTexture())));
	}
	// Returns 4 points of real size. This is affected by your 
	// texture whole size, texture used size, and scale.
	b2Vec2 * GetRealSize()
	{
		static b2Vec2 result[4];
		result[0].x = quad.v[0].tx * GetTexSize().x * _scale.x; result[0].y = quad.v[0].ty * GetTexSize().y * _scale.y;
		result[1].x = quad.v[1].tx * GetTexSize().x * _scale.x; result[1].y = quad.v[1].ty * GetTexSize().y * _scale.y;
		result[2].x = quad.v[2].tx * GetTexSize().x * _scale.x; result[2].y = quad.v[2].ty * GetTexSize().y * _scale.y;
		result[3].x = quad.v[3].tx * GetTexSize().x * _scale.x; result[3].y = quad.v[3].ty * GetTexSize().y * _scale.y;
		return &result[0];
	}
	// Set and get the texture center position.
	void SetPosition(b2Vec2 position)
	{
		b2Vec2 * Size = GetRealSize();
		_pos[0].y = GAME_HEIGHT - position.y;
		_pos[0].x = position.x;
		_pos[1] = _pos[0] + Size[1] - Size[0];
		_pos[2] = _pos[0] + Size[2] - Size[0];
		_pos[3] = _pos[0] + Size[3] - Size[0];
	}
	b2Vec2 GetPosition()
	{
		return b2Vec2(_pos[0].x,GAME_HEIGHT - _pos[0].y);
	}
	// Return 4 corners 
	b2Vec2 * GetCorners()
	{
		return &_pos[0];
	}
	// Apply to 4 corners the Rotate from origin function.
	// Also get inverted.
	b2Vec2 * GetCornersAngled()
	{
		b2Vec2 * UnAngled = GetCorners();
		b2Vec2 origin = GetCenter();
		static b2Vec2 result[4];
		result[0] = RotateFromOrigin(GetCenter(),UnAngled[0],SexagesimalToRadian(_angle));
		result[1] = RotateFromOrigin(GetCenter(),UnAngled[1],SexagesimalToRadian(_angle));
		result[2] = RotateFromOrigin(GetCenter(),UnAngled[2],SexagesimalToRadian(_angle));
		result[3] = RotateFromOrigin(GetCenter(),UnAngled[3],SexagesimalToRadian(_angle));
		if (Inverted)
		{
			b2Vec2 buf;
			buf = result[0];
			result[0] = result[1];
			result[1] = buf;
			buf = result[2];
			result[2] = result[3];
			result[3] = buf;
		}
		return &result[0];
	}
	// Angle, and scale getters and setters.
	void SetAngle(float32 newangle)
	{
		_angle = newangle;
	}
	float32 GetAngle()
	{
		return _angle;
	}
	b2Vec2 GetScale()
	{
		return _scale;
	}
	void SetScale(b2Vec2 sc)
	{
		_scale = sc;
		SetPosition(GetPosition());
	}
};

class SpriteSequence
{
private:
	float32 timeleft;
	int ActualSprite;
	DWORD _color;
	Sprite _spr;
	void SetSpriteRegion(int n)
	{
		ActualSprite = n;
		int w = INT(GetSprite()->GetTexSize().x);
		int h = INT(GetSprite()->GetTexSize().y);
		int x = n * INT(SpriteSize.x);
		int y = 0;
		while(x > w)
		{
			y += INT(SpriteSize.y);
			x -= w;
		}
		float32 vertex[2][4];
		vertex[0][0] = FLOAT(x/w); vertex[1][0] = FLOAT(y/h);
		vertex[0][1] = (SpriteSize.x + FLOAT(x))/w; vertex[1][1] = FLOAT(y/h);
		vertex[0][2] = (SpriteSize.x + x)/w; vertex[1][2] = (SpriteSize.y + y)/h;
		vertex[0][3] = FLOAT(x/w); vertex[1][3] = (SpriteSize.y + y)/h;
		GetSprite()->SetTexSize(vertex[0],vertex[1]);
	}
	void SetNextSpriteRegion()
	{
		if (ActualSprite >= LastSprite)
			ActualSprite = -1;
		SetSpriteRegion(ActualSprite + 1);
	}
public:
	b2Vec2 SpriteSize;
	int FirstSprite;
	int LastSprite;
	float32 delay;

	SpriteSequence()
	{
		SpriteSize = b2Vec2_zero;
		timeleft = -1;
		delay = 0;
		FirstSprite = LastSprite = ActualSprite = 0;
	}
	Sprite * GetSprite()
	{
		return &_spr;
	}
	void Update(float32 time)
	{
		if(timeleft == -1)
			timeleft = delay;
		timeleft -= time;
		if (timeleft <= 0)
			SetNextSpriteRegion();
	}
	void Draw()
	{
		_spr.Draw();
	}
	void SetColor(DWORD col){_color = col;}
	void SetPosition(b2Vec2 pos)
	{
		_spr.SetPosition(pos);
	}
};
#endif
